#include "mainwindow.h"
#include <QFileDialog>
#include <QTextStream>
#include "ui_mainwindow.h"
#include "node.h"
#include "maze.h"


MainWindow::MainWindow(QApplication *a,QWidget *parent)
        : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    A = new StarAlgorithm(M);
    lDialog = new labDialog();
    app = a;
    connect(ui->btn_start,SIGNAL(clicked()),this,SLOT(start()));
    connect(ui->btn_reset,SIGNAL(clicked()),this,SLOT(reset()));
    connect(lDialog->solveAc,SIGNAL(triggered()),this,SLOT(start()));
    connect(lDialog->resetAc,SIGNAL(triggered()),this,SLOT(reset()));

    connect(ui->actionOpen,SIGNAL(triggered()),this,SLOT(openFile()));
    connect(ui->actionSave,SIGNAL(triggered()),this,SLOT(saveFile()));
    connect(ui->actionClose,SIGNAL(triggered()),lDialog,SLOT(hide()));
    connect(ui->sp_Hor,SIGNAL(valueChanged(double)),A,SLOT(setPesoHorizontal(double)));
    connect(ui->sp_Vert,SIGNAL(valueChanged(double)),A,SLOT(setPesoVertical(double)));
    connect(ui->sp_Diag,SIGNAL(valueChanged(double)),A,SLOT(setPesoDiagonal(double)));
    connect(lDialog,SIGNAL(actSignal(int,int,ACTION)),this,SLOT(repaint(int,int,ACTION)));
    connect(ui->wOpen,SIGNAL(currentRowChanged(int)),this,SLOT(printParcOpenSlot(int)));
    connect(ui->wClose,SIGNAL(currentRowChanged(int)),this,SLOT(printParcCloseSlot(int)));
    connect(ui->wOpen,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(itemClickedOpen(QListWidgetItem*)));
    connect(ui->actionExit,SIGNAL(triggered()),a,SLOT(quit()));
    connect(ui->cb_pesoDiagonal,SIGNAL(stateChanged(int)),this,SLOT(pesoAutoSlot(int)));
    connect(this,SIGNAL(destroyed()),a,SLOT(quit()));
    ui->sp_Hor->setValue(1.5);
    ui->sp_Vert->setValue(1.5);
    ui->sp_Diag->setValue(1.5);
}

void MainWindow::closeEvent ( QCloseEvent * event ) {
    app->quit();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::saveFile() {
    QFile file;
    QString fileName;
    fileName = QFileDialog::getSaveFileName(this,tr("Open Lab"),"", tr("Lab Files (*.txt *.lab)"));
    file.setFileName(fileName);
    if(!file.open(QIODevice::WriteOnly)){
        return;
    }

    QTextStream out(&file);
    out << M.row << " " << M.col << " " << A->pesoHorizontal << " " << A->pesoVertical << "\n";
    for(int i = 0; i < M.row; i++){
        for(int j = 0; j < M.col; j++) {
            switch(M.getSaddles(i,j)) {
            case EMPTY:
                out << 0 << " ";
                break;
            case WALL:
                out << 1 << " ";
                break;
            case INIT:
                out << 2 << " ";
                break;
            case END:
                out << 3 << " ";
                break;
            default:
                out << 9 << " ";
                break;
            }
        }
        out << "\n";
    }
    file.close();
}

void MainWindow::openFile() {
    QFile file;
    QString fileName;
    int row,col,CustoHorizontal,CustoVertical,tmp;
    double CustoDiagonal;

    fileName = QFileDialog::getOpenFileName(this,tr("Open Lab"),"", tr("Lab Files (*.txt *.lab)"));
    file.setFileName(fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    QTextStream in(&file);

    if(!in.atEnd())
        in >> row;
    if(!in.atEnd())
        in >> col;
    M = Maze(row,col);

    if(!in.atEnd())
        in >> CustoHorizontal;
    if(!in.atEnd())
        in >> CustoVertical;

    CustoDiagonal = sqrt(pow(CustoHorizontal,2) + pow(CustoVertical,2));
    for(int i = 0; i < row; i++){
        for(int j = 0; j < col; j++) {
            if(!in.atEnd()) {
                in >> tmp;
                switch(tmp) {
                case 0:
                    M.setSaddles(i,j,EMPTY);
                    break;
                case 1:
                    M.setSaddles(i,j,WALL);
                    break;
                case 2:
                    M.setInicial(Node(i,j));
                    break;
                case 3:
                    M.setFinal(Node(i,j));
                    break;
                default:
                    break;

                }
            }
        }
    }
    A->SetParams(M);
    A->setPesoHorizontal(CustoHorizontal);
    ui->sp_Hor->setValue(CustoHorizontal);

    A->setPesoVertical(CustoVertical);
    ui->sp_Vert->setValue(CustoVertical);

    A->setPesoDiagonal(CustoDiagonal);
    ui->sp_Diag->setValue(CustoDiagonal);

    this->reset();
    this->Paint();
    lDialog->show();
    file.close();
}

void MainWindow::Paint() {
    NodeGraphics *tmp = NULL;
    A->SetParams(M);
    lDialog->newScene();
    for(int i = 0; i < M.row; i++) {
        for (int j = 0; j < M.col; j++) {
            tmp = new NodeGraphics();
            connect(tmp,SIGNAL(repaint(int,int,ACTION)),this,SLOT(repaint(int,int,ACTION)));
            connect(tmp,SIGNAL(menuSignal(int,int,QPoint)),lDialog,SLOT(showMenu(int,int,QPoint)));
            tmp->setPos(j * 17 , i * 17 );
            tmp->setRowCol(i,j);
            lDialog->scene->addItem(tmp);
            NodeGraphics::NodesMap[pair(i,j)] = tmp;
        }
    }
    A->updateGraph();
}

void MainWindow::repaint(int row, int col, ACTION a) {
    A->updateGraph();
    switch (a) {
    case SET_SADDLES:
        if(!A->resolved){
            if(M.getSaddles(row,col) == WALL) {
                M.setSaddles(row,col,EMPTY);
                A->M.setSaddles(row,col,EMPTY);
            } else {
                M.setSaddles(row,col,WALL);
                A->M.setSaddles(row,col,WALL);
            }
        }
        A->updateGraph();
        break;
    case SHOW_WAY:
        A->printParc(row,col);
        break;
    case SET_INIT:
        if(!A->resolved){
            A->M.setInicial(Node(row,col));
            M.setInicial(Node(row,col));
        }
        A->updateGraph();
        break;
    case SET_END:
        if(!A->resolved){
            A->M.setFinal(Node(row,col));
            M.setFinal(Node(row,col));
        }
        A->updateGraph();
        break;
    case SHOW_HIDE_LISTS:
        A->showHideLists();
        A->updateGraph();
        break;
     case UPDATE:
        A->updateGraph();
        break;
    }

    lDialog->update();
}

void MainWindow::start() {
    lDialog->show();
    A->SetParams(M);
    A->Start();
    A->updateGraph();
    lDialog->setFocus();
    lDialog->update();
    updateLists();
}


void MainWindow::reset() {
    std::map<pair,NodeGraphics*,pairLess>::iterator end =  NodeGraphics::NodesMap.end();
    std::map<pair,NodeGraphics*,pairLess>::iterator begin =  NodeGraphics::NodesMap.begin();
    std::cout << "1" << std::endl;
    for(; begin != end; begin++){
        lDialog->scene->removeItem((*begin).second);
        delete (*begin).second;
    };
    std::cout << "2" << std::endl;
    ui->wClose->clear();\
    std::cout << "2.1" << std::endl;
    ui->wOpen->clear();
    std::cout << "3" << std::endl;
    NodeGraphics::NodesMap.clear();;
    std::cout << "4" << std::endl;
    lDialog->update();
    std::cout << "5" << std::endl;
    this->Paint();
}

QString MainWindow::loadStyleSheet(const QString &sheetName)
{
    QFile file(":/qss/" + sheetName.toLower() + ".qss");
    file.open(QFile::ReadOnly);
    QString styleSheet = QLatin1String(file.readAll());
    return styleSheet;
}

void MainWindow::updateLists() {
    ListNode::iterator bg = A->Close.begin();
    ListNode::iterator end = A->Close.end();
    for(; bg != end; bg++){
        ui->wClose->addItem("(" + QString::number((*bg)->row) + "," + QString::number((*bg)->col) + ")");
    }

    bg = A->Open.begin();
    end = A->Open.end();

    for(; bg != end; bg++){
        ui->wOpen->addItem("(" + QString::number((*bg)->row) + "," + QString::number((*bg)->col) + ")");
    }
}

void MainWindow::printParcOpenSlot( int currentRow ){
    A->updateGraph();
    A->printParc(A->Open[currentRow]->row,A->Open[currentRow]->col);
}

void MainWindow::printParcCloseSlot( int currentRow ){
    A->updateGraph();
    A->printParc(A->Close[currentRow]->row,A->Close[currentRow]->col);
}


void MainWindow::itemClickedOpen( QListWidgetItem * item ){
    printParcOpenSlot(ui->wOpen->currentRow());

}

void MainWindow::pesoAutoSlot(int state) {
    if(state == Qt::Unchecked) {
        ui->sp_Diag->setEnabled(true);
    } else {
        ui->sp_Diag->setValue(sqrt(pow(ui->sp_Hor->value(),2) + pow(ui->sp_Vert->value(),2)));
        ui->sp_Diag->setEnabled(false);
        A->setPesoDiagonal(ui->sp_Diag->value());
    }
}



